home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / tde3.zip / WINDOW.C < prev    next >
C/C++ Source or Header  |  1993-06-05  |  39KB  |  1,248 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - window module
  10.  * Purpose: This file contains the code associated with opening and sizing
  11.  *           windows, and also displaying the help window.
  12.  * File:    window.c
  13.  * Author:  Douglas Thomson
  14.  * System:  this file is intended to be system-independent
  15.  * Date:    October 12, 1989
  16.  */
  17. /*********************  end of original comments   ********************/
  18.  
  19.  
  20. /*
  21.  * The window routines have been EXTENSIVELY rewritten.  Some routines were
  22.  * changed so only one logical function is carried out, eg. 'initialize_window'.
  23.  * I like the Microsoft way of resizing windows - just press the up and down
  24.  * arrows to adjust the window to desired size.  I also like pressing one key
  25.  * to change windows.  All of which are implemented in TDE.
  26.  *
  27.  * In TDE, version 1.4, I added support for vertical windows.
  28.  *
  29.  * New editor name:  TDE, the Thomson-Davis Editor.
  30.  * Author:           Frank Davis
  31.  * Date:             June 5, 1991, version 1.0
  32.  * Date:             July 29, 1991, version 1.1
  33.  * Date:             October 5, 1991, version 1.2
  34.  * Date:             January 20, 1992, version 1.3
  35.  * Date:             February 17, 1992, version 1.4
  36.  * Date:             April 1, 1992, version 1.5
  37.  * Date:             June 5, 1992, version 2.0
  38.  * Date:             October 31, 1992, version 2.1
  39.  * Date:             April 1, 1993, version 2.2
  40.  * Date:             June 5, 1993, version 3.0
  41.  *
  42.  * This modification of Douglas Thomson's code is released into the
  43.  * public domain, Frank Davis.  You may distribute it freely.
  44.  */
  45.  
  46. #include "tdestr.h"
  47. #include "common.h"
  48. #include "define.h"
  49. #include "tdefunc.h"
  50.  
  51.  
  52. /*
  53.  * Name:    initialize_window
  54.  * Purpose: To open a new window
  55.  * Date:    June 5, 1991
  56.  * Returns: OK if window opened successfully
  57.  *          ERROR if anything went wrong
  58.  * Notes:   If this is first window, then set up as normal displayed window;
  59.  *          otherwise, make the present window invisible and open a new
  60.  *          window in the same screen location as the old one.
  61.  */
  62. int  initialize_window( void )
  63. {
  64. int  top;
  65. int  bottom;
  66. int  start_col;
  67. int  end_col;
  68. WINDOW *wp;        /* used for scanning windows */
  69. WINDOW *window;
  70. register file_infos *fp;     /* used for scanning files */
  71. register int rc;
  72. line_list_ptr ll;
  73. line_list_ptr temp_ll;
  74.  
  75.    rc = OK;
  76.    window = g_status.current_window;
  77.    fp = g_status.current_file;
  78.    if (window == NULL) {
  79.       /*
  80.        * special case if this is the first window on screen.
  81.        */
  82.       top = start_col = 0;
  83.       bottom  = g_display.nlines;
  84.       end_col = g_display.ncols - 1;
  85.    } else {
  86.       /*
  87.        * else put the new window in same place as current window.
  88.        *  make current window invisible.  new window becomes current window.
  89.        */
  90.       top       = window->top_line - 1;
  91.       bottom    = window->bottom_line;
  92.       start_col = window->start_col;
  93.       end_col   = window->end_col;
  94.    }
  95.  
  96.    assert( top < bottom );
  97.    assert( start_col < end_col );
  98.    assert( fp != NULL );
  99.  
  100.    if (create_window( &wp, top, bottom, start_col, end_col, fp ) == ERROR) {
  101.       /*
  102.        * out of memory
  103.        */
  104.       error( WARNING, bottom, main4 );
  105.  
  106.       /*
  107.        * This is a real nuisance. We had room for the file and the
  108.        *  file structure, but not enough for the window as well.
  109.        * Now we must free all the memory that has already been
  110.        *  allocated.
  111.        */
  112.       if (fp->ref_count == 0) {
  113.  
  114.          /*
  115.           * remove fp from file pointer list.
  116.           */
  117.          if (fp->prev != NULL)
  118.             fp->prev->next = fp->next;
  119.          else
  120.             g_status.file_list = fp->next;
  121.  
  122.          if (fp->next != NULL)
  123.             fp->next->prev = fp->prev;
  124.  
  125.          /*
  126.           * free the undo stack, line pointers, and linked list.
  127.           */
  128.  
  129.          ll = fp->undo_top;
  130.          while (ll != NULL) {
  131.             temp_ll = ll->next;
  132.             if (ll->line != NULL)
  133.                my_free( ll->line );
  134.             my_free( ll );
  135.             ll = temp_ll;
  136.          }
  137.  
  138.          ll = fp->line_list;
  139.          while (ll != NULL) {
  140.             temp_ll = ll->next;
  141.             if (ll->line != NULL)
  142.                my_free( ll->line );
  143.             my_free( ll );
  144.             ll = temp_ll;
  145.          }
  146.  
  147. #if defined( __MSC__ )
  148.          _fheapmin( );
  149. #endif
  150.  
  151.          free( fp );
  152.          wp = g_status.current_window;
  153.          if (wp != NULL && wp->visible)
  154.             g_status.current_file = wp->file_info;
  155.          else
  156.             g_status.stop = TRUE;
  157.       }
  158.       rc = ERROR;
  159.    }
  160.  
  161.    if (rc != ERROR) {
  162.       /*
  163.        * set up the new cursor position as appropriate
  164.        */
  165.       wp->ccol = wp->start_col;
  166.       wp->rcol = wp->bcol = 0;
  167.       wp->rline = 1L;
  168.       wp->ll    = fp->line_list;
  169.       wp->visible = TRUE;
  170.       wp->letter = fp->next_letter++;
  171.       if (window != NULL)
  172.          window->visible = FALSE;
  173.  
  174.       /*
  175.        * the new window becomes the current window.
  176.        */
  177.       g_status.current_window = wp;
  178.    }
  179.    return( rc );
  180. }
  181.  
  182.  
  183. /*
  184.  * Name:    next_window
  185.  * Purpose: To move to the next visible window.
  186.  * Date:    June 5, 1991
  187.  * Passed:  window:  pointer to current window
  188.  * Notes:   Start with current window.  If next window exists then go to it
  189.  *           else go to the first (top) window on screen.
  190.  *          When I added vertical windows, finding the "correct" next
  191.  *           window became extremely, unnecessarily, unmanageably complicated.
  192.  *           let's just use a simple procedure to find the first available,
  193.  *           visible, next window.
  194.  */
  195. int  next_window( WINDOW *window )
  196. {
  197. register WINDOW *wp;
  198. int  change;
  199.  
  200.    if (window != NULL) {
  201.       change = FALSE;
  202.       /*
  203.        * start with current window and look for first next
  204.        *  visible window
  205.        */
  206.       wp = window->next;
  207.       while (wp != NULL) {
  208.          if (wp->visible) {
  209.             change = TRUE;
  210.             break;
  211.          }
  212.          wp = wp->next;
  213.       }
  214.  
  215.       /*
  216.        * if we haven't found a visible window yet, go to the beginning of
  217.        *  the list until we find a visible window.
  218.        */
  219.       if (!change) {
  220.          wp = g_status.window_list;
  221.          while (wp != window) {
  222.             if (wp->visible) {
  223.                change = TRUE;
  224.                break;
  225.             }
  226.             wp = wp->next;
  227.          }
  228.       }
  229.       if (change == TRUE) {
  230.          entab_linebuff( );
  231.          un_copy_line( window->ll, window, TRUE );
  232.          g_status.current_window = wp;
  233.          g_status.current_file = wp->file_info;
  234.       }
  235.    }
  236.    return( OK );
  237. }
  238.  
  239.  
  240. /*
  241.  * Name:    prev_window
  242.  * Purpose: To move to the previous visible window.
  243.  * Date:    June 5, 1991
  244.  * Passed:  window:  pointer to current window
  245.  * Notes:   Start with current window.  If previous window exists then go to
  246.  *           it else go to the last (bottom) window on screen.  Opposite of
  247.  *           next_window.
  248.  *          when I added vertical windows, finding the "correct" previous
  249.  *           window became extremely, unnecessarily, unmanageably complicated.
  250.  *           let's just use a simple procedure to find the first available,
  251.  *           visible, previous window.
  252.  */
  253. int  prev_window( WINDOW *window )
  254. {
  255. register WINDOW *wp;
  256. int  change;
  257.  
  258.    if (window != NULL) {
  259.       change = FALSE;
  260.  
  261.       /*
  262.        * start with current window and look for first previous
  263.        *  visible window
  264.        */
  265.       wp = window->prev;
  266.       while (wp != NULL) {
  267.          if (wp->visible) {
  268.             change = TRUE;
  269.             break;
  270.          }
  271.          wp = wp->prev;
  272.       }
  273.  
  274.       /*
  275.        * if we haven't found a visible window yet, go to the end of
  276.        *  the list and work backwards until we find a visible window.
  277.        */
  278.       if (!change) {
  279.          wp = window->next;
  280.          if (wp != NULL) {
  281.             while (wp->next != NULL)
  282.                wp = wp->next;
  283.             while (wp != window) {
  284.                if (wp->visible) {
  285.                   change = TRUE;
  286.                   break;
  287.                }
  288.                wp = wp->prev;
  289.             }
  290.          }
  291.       }
  292.       if (change == TRUE) {
  293.          entab_linebuff( );
  294.          un_copy_line( window->ll, window, TRUE );
  295.          g_status.current_window = wp;
  296.          g_status.current_file = wp->file_info;
  297.       }
  298.    }
  299.    return( OK );
  300. }
  301.  
  302.  
  303. /*
  304.  * Name:    split_horizontal
  305.  * Purpose: To split screen horizontally at the cursor.
  306.  * Date:    June 5, 1991
  307.  * Passed:  window:  pointer to current window
  308.  * Notes:   split the screen horizontally at the cursor position.
  309.  */
  310. int  split_horizontal( WINDOW *window )
  311. {
  312. register WINDOW *wp;
  313. register WINDOW *win;   /* register pointer for window */
  314. WINDOW *temp;
  315. file_infos *file;       /* file structure for file belonging to new window */
  316. int  rc;
  317.  
  318.    rc = OK;
  319.    win = window;
  320.    if ( win != NULL) {
  321.  
  322.       /*
  323.        * check that there is room for the window
  324.        */
  325.       if (win->bottom_line - win->cline < 2) {
  326.          /*
  327.           * move cursor up first
  328.           */
  329.          error( WARNING, win->bottom_line, win1 );
  330.          rc = ERROR;
  331.       } else {
  332.          file = win->file_info;
  333.  
  334.          assert( file != NULL );
  335.  
  336.          if (create_window( &temp, win->cline+1, win->bottom_line,
  337.                             win->start_col, win->end_col, file ) == ERROR) {
  338.             /*
  339.              * out of memory
  340.              */
  341.             error( WARNING, win->bottom_line, main4 );
  342.             rc = ERROR;
  343.          }
  344.          if (rc == OK  &&  temp != NULL) {
  345.             entab_linebuff( );
  346.             un_copy_line( win->ll, win, TRUE );
  347.             wp = temp;
  348.             /*
  349.              * record that the current window has lost some lines from
  350.              *  the bottom for the new window, and adjust its page size
  351.              *  etc accordingly.
  352.              */
  353.             win->bottom_line = win->cline;
  354.             setup_window( win );
  355.             display_current_window( win );
  356.  
  357.             /*
  358.              * set up the new cursor position as appropriate
  359.              */
  360.             wp->rcol = win->rcol;
  361.             wp->ccol = win->ccol;
  362.             wp->bcol = win->bcol;
  363.             wp->rline = win->rline;
  364.             wp->bin_offset = win->bin_offset;
  365.             wp->ll    = win->ll;
  366.             wp->cline = wp->cline + win->cline - (win->top_line + win->ruler);
  367.             if (wp->cline > wp->bottom_line)
  368.                wp->cline = wp->bottom_line;
  369.             wp->visible = TRUE;
  370.             wp->vertical = win->vertical;
  371.             wp->letter = file->next_letter++;
  372.             wp->ruler  = mode.ruler;
  373.  
  374.             /*
  375.              * the new window becomes the current window.
  376.              */
  377.             g_status.current_window = wp;
  378.  
  379.             show_window_count( g_status.window_count );
  380.             show_window_header( wp );
  381.             display_current_window( wp );
  382.             if (wp->vertical)
  383.                show_vertical_separator( wp );
  384.             make_ruler( wp );
  385.             show_ruler( wp );
  386.             rc = OK;
  387.          }
  388.       }
  389.    } else
  390.       rc = ERROR;
  391.    return( rc );
  392. }
  393.  
  394.  
  395. /*
  396.  * Name:    split_vertical
  397.  * Purpose: To split screen vertically at the cursor.
  398.  * Date:    June 5, 1991
  399.  * Passed:  window:  pointer to current window
  400.  * Notes:   split the screen vertically at the cursor position.
  401.  */
  402. int  split_vertical( WINDOW *window )
  403. {
  404. register WINDOW *wp;
  405. register WINDOW *win;   /* register pointer for window */
  406. WINDOW *temp;
  407. file_infos *file;       /* file structure for file belonging to new window */
  408. int  rc;
  409.  
  410.    rc = OK;
  411.    win = window;
  412.    if (win != NULL) {
  413.  
  414.       /*
  415.        * check that there is room for the window
  416.        */
  417.       if (win->start_col + 15 > win->ccol) {
  418.          /*
  419.           * move cursor right first
  420.           */
  421.          error( WARNING, win->bottom_line, win2 );
  422.          rc = ERROR;
  423.       } else if (win->end_col - 15 < win->ccol) {
  424.          /*
  425.           * move cursor left first
  426.           */
  427.          error( WARNING, win->bottom_line, win3 );
  428.          rc = ERROR;
  429.       } else {
  430.          file = win->file_info;
  431.  
  432.          assert( file != NULL );
  433.  
  434.          if (create_window( &temp, win->top_line-1, win->bottom_line,
  435.                             win->ccol+1, win->end_col, file ) == ERROR) {
  436.             /*
  437.              * out of memory
  438.              */
  439.             error( WARNING, win->bottom_line, main4 );
  440.             rc = ERROR;
  441.          }
  442.  
  443.          if (rc == OK  &&  temp != NULL) {
  444.             entab_linebuff( );
  445.             un_copy_line( win->ll, win, TRUE );
  446.             wp = temp;
  447.  
  448.             /*
  449.              * record that the current window has lost some columns from
  450.              *  the window to the left for the new window
  451.              */
  452.             win->ccol = win->end_col = win->ccol - 1;
  453.             win->rcol--;
  454.             win->vertical = TRUE;
  455.             show_window_header( win );
  456.             show_vertical_separator( win );
  457.             display_current_window( win );
  458.             make_ruler( win );
  459.             show_ruler( win );
  460.             show_ruler_pointer( win );
  461.  
  462.             /*
  463.              * set up the new cursor position as appropriate
  464.              */
  465.             wp->rcol = win->rcol;
  466.             wp->ccol = wp->start_col + win->ccol - win->start_col;
  467.             if (wp->ccol > wp->end_col)
  468.                wp->ccol = wp->end_col;
  469.             wp->bcol  = win->bcol;
  470.             wp->rline = win->rline;
  471.             wp->bin_offset = win->bin_offset;
  472.             wp->ll       = win->ll;
  473.             wp->cline    = win->cline;
  474.             wp->visible  = TRUE;
  475.             wp->vertical = TRUE;
  476.             wp->letter   = file->next_letter++;
  477.             wp->ruler    = mode.ruler;
  478.  
  479.             /*
  480.              * the new window becomes the current window.
  481.              */
  482.             g_status.current_window = wp;
  483.  
  484.             check_virtual_col( wp, wp->rcol, wp->ccol );
  485.             wp->file_info->dirty = FALSE;
  486.             show_window_count( g_status.window_count );
  487.             show_window_header( wp );
  488.             display_current_window( wp );
  489.             make_ruler( wp );
  490.             show_ruler( wp );
  491.          }
  492.       }
  493.    } else
  494.       rc = ERROR;
  495.    return( rc );
  496. }
  497.  
  498.  
  499. /*
  500.  * Name:    show_vertical_separator
  501.  * Purpose: To separate vertical screens
  502.  * Date:    June 5, 1991
  503.  * Passed:  window:  pointer to current window
  504.  */
  505. void show_vertical_separator( WINDOW *window )
  506. {
  507. int  i;
  508. int  line;
  509. int  col;
  510.  
  511.    line = window->top_line - 1;
  512.    col  = window->end_col + 1;
  513.    if (col < g_display.ncols - 1) {
  514.       i = window->bottom_line - line;
  515.  
  516.       assert( i <= g_display.nlines );
  517.  
  518.       while (i-- >= 0)
  519.          c_output( VERTICAL_CHAR, col, line++, g_display.head_color );
  520.    }
  521. }
  522.  
  523.  
  524. /*
  525.  * Name:    size_window
  526.  * Purpose: To change the size of the current and one other window.
  527.  * Date:    June 5, 1991
  528.  * Passed:  window:  pointer to current window
  529.  * Notes:   Use the Up and Down arrow keys to make the current window
  530.  *           bigger or smaller.  The window above will either grow
  531.  *           or contract accordingly.
  532.  */
  533. int  size_window( WINDOW *window )
  534. {
  535. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  536. int  func;
  537. int  c;
  538. int  resize;
  539. int  show_above_ruler;
  540. int  old_bottom_line;
  541. int  old_top_line;
  542. int  new_bottom_line;
  543. int  new_top_line;
  544. register WINDOW *above;
  545. register WINDOW *win;
  546.  
  547.    win = window;
  548.    if (win->top_line != 1 && !win->vertical) {
  549.       entab_linebuff( );
  550.       un_copy_line( win->ll, win, TRUE );
  551.       save_screen_line( 0, win->bottom_line, line_buff );
  552.  
  553.       /*
  554.        * press up or down to change window size
  555.        */
  556.       set_prompt( win4, win->bottom_line );
  557.  
  558.       /*
  559.        * resizing only affects current window and above visible window
  560.        */
  561.       above = g_status.window_list;
  562.       while (above->bottom_line + 2 != win->top_line || !above->visible)
  563.          above = above->next;
  564.       if (above->vertical)
  565.          /*
  566.           * cannot resize vertical window
  567.           */
  568.          error( WARNING, win->bottom_line, win5 );
  569.       else {
  570.          old_top_line = win->top_line;
  571.          old_bottom_line = above->bottom_line;
  572.          show_above_ruler = FALSE;
  573.          for (func=0; func != AbortCommand && func != Rturn; ) {
  574.  
  575.             /*
  576.              * If user has redined the ESC and Return keys, make them Rturn and
  577.              *  AbortCommand in this function.
  578.              */
  579.             c = getkey( );
  580.             func = getfunc( c );
  581.             if (c == RTURN || func == NextLine || func == BegNextLine)
  582.                func = Rturn;
  583.             else if (c == ESC)
  584.                func = AbortCommand;
  585.             resize = FALSE;
  586.  
  587.             /*
  588.              * if LineUp, make current window top line grow and bottom line
  589.              *  of above window shrink.  if window movement covers up current
  590.              *  line of window then we must adjust logical line and real line.
  591.              */
  592.             if (func == LineUp) {
  593.                if (above->bottom_line > above->top_line + above->ruler) {
  594.                   if (win->rline == (win->cline - (win->top_line+win->ruler-1)))
  595.                      --win->cline;
  596.                   --win->top_line;
  597.                   if (above->cline == above->bottom_line)
  598.                      --above->cline;
  599.                   --above->bottom_line;
  600.                   resize = TRUE;
  601.                   if (mode.ruler) {
  602.                      if (win->ruler == FALSE) {
  603.                         if (win->cline == win->top_line)
  604.                            ++win->cline;
  605.                         if (win->cline > win->bottom_line)
  606.                            win->cline = win->bottom_line;
  607.                         win->ruler = TRUE;
  608.                      }
  609.                   }
  610.                }
  611.  
  612.             /*
  613.              * if LineDown, make current window top line shrink and bottom line
  614.              *  of above window grow.  if window movement covers up current
  615.              *  line of window then we must adjust logical line and real line.
  616.              */
  617.             } else if (func == LineDown) {
  618.                if (win->bottom_line > win->top_line + win->ruler) {
  619.                   if (win->cline == win->top_line + win->ruler)
  620.                      ++win->cline;
  621.                   ++win->top_line;
  622.                   ++above->bottom_line;
  623.                   resize = TRUE;
  624.                   if (mode.ruler) {
  625.                      if (above->ruler == FALSE) {
  626.                         if (above->cline == above->top_line)
  627.                            ++above->cline;
  628.                         if (above->cline > above->bottom_line)
  629.                            above->cline = above->bottom_line;
  630.                         above->ruler = TRUE;
  631.                         make_ruler( above );
  632.                         show_above_ruler = TRUE;
  633.                      }
  634.                   }
  635.                }
  636.             }
  637.  
  638.             /*
  639.              * if we resize a window, then update window size and current and
  640.              *  real lines if needed.
  641.              */
  642.             if (resize == TRUE) {
  643.                setup_window( above );
  644.                display_current_window( above );
  645.                if (show_above_ruler) {
  646.                   show_ruler( above );
  647.                   show_ruler_pointer( above );
  648.                   show_above_ruler = FALSE;
  649.                }
  650.                setup_window( win );
  651.                show_window_header( win );
  652.                win->ruler = mode.ruler;
  653.                make_ruler( win );
  654.                show_ruler( win );
  655.                show_ruler_pointer( win );
  656.                display_current_window( win );
  657.                save_screen_line( 0, win->bottom_line, line_buff );
  658.  
  659.                /*
  660.                 * press up or down to change window size
  661.                 */
  662.                set_prompt( win4, win->bottom_line );
  663.             }
  664.          }
  665.          new_top_line = win->top_line;
  666.          new_bottom_line = above->bottom_line;
  667.          for (above=g_status.window_list; above != NULL; above=above->next) {
  668.             if (!above->visible) {
  669.                if (above->bottom_line == old_bottom_line) {
  670.                   above->bottom_line = new_bottom_line;
  671.                   if (above->cline < new_bottom_line)
  672.                      above->cline = new_bottom_line;
  673.                   setup_window( above );
  674.                } else if (above->top_line == old_top_line) {
  675.                   above->top_line = new_top_line;
  676.                   if (above->cline < new_top_line)
  677.                      above->cline = new_top_line;
  678.                   if ((long)(above->cline+1L - (above->top_line+above->ruler)) >
  679.                                                                 above->rline)
  680.                      above->cline = (int)above->rline + above->top_line +
  681.                                      above->ruler - 1;
  682.                   setup_window( above );
  683.                }
  684.             }
  685.          }
  686.       }
  687.       restore_screen_line( 0, win->bottom_line, line_buff );
  688.    } else {
  689.      if (win->vertical)
  690.         /*
  691.          * cannot resize vertical window
  692.          */
  693.         error( WARNING, win->bottom_line, win5 );
  694.      else
  695.         /*
  696.          * cannot resize top window
  697.          */
  698.         error( WARNING, win->bottom_line, win6 );
  699.    }
  700.    return( OK );
  701. }
  702.  
  703.  
  704. /*
  705.  * Name:    zoom_window
  706.  * Purpose: To blow-up current window.
  707.  * Date:    September 1, 1991
  708.  * Passed:  window:  pointer to current window
  709.  * Notes:   Make all windows, visible and hidden, full size.
  710.  */
  711. int  zoom_window( WINDOW *window )
  712. {
  713. register WINDOW *wp;
  714.  
  715.    if (window != NULL) {
  716.       entab_linebuff( );
  717.       un_copy_line( window->ll, window, TRUE );
  718.       for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  719.          if (wp != window && wp->visible)
  720.             wp->visible = FALSE;
  721.  
  722.          /*
  723.           * can't diff one window, reset the diff
  724.           */
  725.          diff.defined = FALSE;
  726.          if (wp->top_line != 1)
  727.             wp->cline = wp->cline - (wp->top_line+wp->ruler) + 1;
  728.          wp->top_line = 1;
  729.          wp->bottom_line = g_display.nlines;
  730.          wp->end_col   = g_display.ncols - 1;
  731.          wp->start_col = 0;
  732.          wp->vertical  = FALSE;
  733.          check_virtual_col( wp, wp->rcol, wp->ccol );
  734.          make_ruler( wp );
  735.       }
  736.       redraw_screen( window );
  737.       show_ruler( window );
  738.    }
  739.    return( OK );
  740. }
  741.  
  742.  
  743. /*
  744.  * Name:    next_hidden_window
  745.  * Purpose: To display the window that is "behind" current window.
  746.  * Date:    September 1, 1991
  747.  * Passed:  window:  pointer to current window
  748.  */
  749. int  next_hidden_window( WINDOW *window )
  750. {
  751. int  poof = FALSE;
  752. register WINDOW *wp;
  753.  
  754.    if (window != NULL) {
  755.  
  756.       /*
  757.        * look for next hidden window starting with current window.
  758.        */
  759.       wp = window;
  760.       for (wp=window->next; wp != NULL && !poof; ) {
  761.          if (!wp->visible)
  762.             poof = TRUE;
  763.          else
  764.             wp = wp->next;
  765.       }
  766.  
  767.       /*
  768.        * if we haven't found an invisible window yet, start looking
  769.        *  for a hidden window from the beginning of the window list.
  770.        */
  771.       if (!poof) {
  772.          for (wp=g_status.window_list; wp != NULL && !poof; ) {
  773.             if (!wp->visible)
  774.                poof = TRUE;
  775.             else
  776.                wp = wp->next;
  777.          }
  778.       }
  779.  
  780.       if (poof) {
  781.          entab_linebuff( );
  782.          un_copy_line( window->ll, window, TRUE );
  783.          wp->cline = window->top_line + window->ruler +
  784.                        (wp->cline - (wp->top_line + wp->ruler));
  785.          wp->top_line = window->top_line;
  786.          wp->bottom_line = window->bottom_line;
  787.          wp->start_col = window->start_col;
  788.          wp->end_col   = window->end_col;
  789.          wp->vertical  = window->vertical;
  790.          if (wp->cline < wp->top_line + wp->ruler)
  791.             wp->cline = wp->top_line + wp->ruler;
  792.          if (wp->cline > wp->bottom_line)
  793.             wp->cline = wp->bottom_line;
  794.          if ((wp->cline+1L - (wp->top_line+wp->ruler)) > wp->rline)
  795.             wp->cline = (int)wp->rline + wp->top_line + wp->ruler - 1;
  796.          check_virtual_col( wp, wp->rcol, wp->ccol );
  797.          wp->visible = TRUE;
  798.          window->visible = FALSE;
  799.          if (diff.defined  &&  (diff.w1 == window  ||  diff.w2 == window))
  800.             diff.defined = FALSE;
  801.          g_status.current_window = wp;
  802.          redraw_current_window( wp );
  803.          make_ruler( wp );
  804.          show_ruler( wp );
  805.       }
  806.    }
  807.    return( OK );
  808. }
  809.  
  810.  
  811. /*
  812.  * Name:    setup_window
  813.  * Purpose: To set the page length and the center line of a window, based
  814.  *           on the top and bottom lines.
  815.  * Date:    June 5, 1991
  816.  * Passed:  window: window to be set up
  817.  */
  818. void setup_window( WINDOW *window )
  819. {
  820.    window->page = window->bottom_line - (window->top_line + window->ruler) -
  821.                   g_status.overlap + 1;
  822.    if (window->page < 1)
  823.       window->page = 1;
  824. }
  825.  
  826.  
  827. /*
  828.  * Name:    finish
  829.  * Purpose: To remove the current window and terminate the program if no
  830.  *           more windows are left.
  831.  * Date:    June 5, 1991
  832.  * Passed:  window:  pointer to current window
  833.  * Notes:   Order of deciding which window becomes current window:
  834.  *          1) If any invisible window with same top and bottom line,
  835.  *          and start_col and end_col, then first invisible one becomes
  836.  *          current window.
  837.  *          2) window above if it exists becomes current window
  838.  *          3) window below if it exists becomes current window
  839.  *          4) window right if it exists becomes current window
  840.  *          5) window left  if it exists becomes current window
  841.  *          6) first available invisible window becomes current window.
  842.  *          When I added vertical windows, this routine became a LOT
  843.  *           more complicated.  To keep things reasonably sane, let's
  844.  *           only close windows that have three common edges, eg.
  845.  *
  846.  *                    ┌──────┬──────────┐
  847.  *                    │      │    no    │
  848.  *                    │      ├─────┬────┤
  849.  *                    │      │yes1 │yes1│
  850.  *                    │  no  ├─────┴────┤
  851.  *                    │      │   yes2   │
  852.  *                    │      ├──────────┤
  853.  *                    │      │   yes2   │
  854.  *                    └──────┴──────────┘
  855.  *
  856.  *          Windows with 'no' cannot be closed.  Windows with 'yes' can
  857.  *          be combined with windows that have the same yes number.
  858.  */
  859. void finish( WINDOW *window )
  860. {
  861. register WINDOW *wp;   /* for scanning other windows */
  862. register WINDOW *win;  /* register pointer for window */
  863. file_infos *file, *fp;  /* for scanning other files */
  864. int  poof;
  865. int  cline;
  866. int  top;
  867. int  bottom;
  868. int  start_col;
  869. int  end_col;
  870. int  max_letter;
  871. int  file_change = FALSE;
  872. line_list_ptr ll;
  873. line_list_ptr temp_ll;
  874.  
  875.    win = window;
  876.    entab_linebuff( );
  877.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  878.       return;
  879.  
  880.    file = win->file_info;
  881.    /*
  882.     * remove all hidden windows that point to same file
  883.     */
  884.    file = win->file_info;
  885.    for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  886.       if (wp->file_info == file) {
  887.          if (!wp->visible) {
  888.             if (wp->prev == NULL) {
  889.                if (wp->next == NULL)
  890.                   g_status.stop = TRUE;
  891.                else
  892.                   g_status.window_list = wp->next;
  893.             } else
  894.                wp->prev->next = wp->next;
  895.             if (wp->next)
  896.                wp->next->prev = wp->prev;
  897.             --wp->file_info->ref_count;
  898.             free( wp );
  899.             --g_status.window_count;
  900.          }
  901.       }
  902.    }
  903.  
  904.    if (win->prev == NULL && win->next == NULL)
  905.       g_status.stop = TRUE;
  906.  
  907.    poof = FALSE;
  908.  
  909.    if (g_status.stop != TRUE) {
  910.       /*
  911.        * see if there are any invisible windows with same top and bottom,
  912.        *  lines, and start_col and end_col as this window.  start looking at
  913.        *  end of window list.
  914.        */
  915.       top       = win->top_line;
  916.       bottom    = win->bottom_line;
  917.       start_col = win->start_col;
  918.       end_col   = win->end_col;
  919.       wp = g_status.window_list;
  920.       if (wp != NULL) {
  921.          while (wp->next != NULL)
  922.             wp = wp->next;
  923.       }
  924.       while (wp != NULL && poof == FALSE) {
  925.          if (wp->top_line == top         &&  wp->bottom_line == bottom  &&
  926.              wp->start_col == start_col  &&  wp->end_col == end_col     &&
  927.                                                               !wp->visible)
  928.             poof = TRUE;
  929.          else
  930.             wp = wp->prev;
  931.       }
  932.  
  933.       if (poof == FALSE) {
  934.          /*
  935.           * see if there are any windows above
  936.           */
  937.          wp = g_status.window_list;
  938.          while (wp != NULL && poof == FALSE) {
  939.             if (wp->bottom_line+2 == win->top_line &&
  940.                 wp->start_col     == win->start_col &&
  941.                      wp->end_col       == win->end_col   && wp->visible) {
  942.                poof = TRUE;
  943.                top  = wp->top_line;
  944.             } else
  945.                wp = wp->next;
  946.          }
  947.          if (poof == FALSE) {
  948.             /*
  949.              * see if there are any windows below
  950.              */
  951.             wp = g_status.window_list;
  952.             while (wp != NULL && poof == FALSE) {
  953.                if (wp->top_line-2 == win->bottom_line  &&
  954.                    wp->start_col     == win->start_col &&
  955.                          wp->end_col    == win->end_col   && wp->visible) {
  956.                   poof = TRUE;
  957.                   bottom = wp->bottom_line;
  958.                } else
  959.                   wp = wp->next;
  960.             }
  961.          }
  962.          if (poof == FALSE) {
  963.             /*
  964.              * see if there are any windows right
  965.              */
  966.             wp = g_status.window_list;
  967.             while (wp != NULL && poof == FALSE) {
  968.                if (wp->top_line    == win->top_line  &&
  969.                          wp->bottom_line == win->bottom_line &&
  970.                          wp->start_col-2 == win->end_col     && wp->visible) {
  971.                   poof = TRUE;
  972.                   end_col = wp->end_col;
  973.                } else
  974.                   wp = wp->next;
  975.             }
  976.          }
  977.          if (poof == FALSE) {
  978.             /*
  979.              * see if there are any windows left
  980.              */
  981.             wp = g_status.window_list;
  982.             while (wp != NULL && poof == FALSE) {
  983.                if (wp->top_line    == win->top_line  &&
  984.                    wp->bottom_line == win->bottom_line &&
  985.                    wp->end_col+2   == win->start_col   && wp->visible) {
  986.                   poof = TRUE;
  987.                   start_col = wp->start_col;
  988.                } else
  989.                   wp = wp->next;
  990.             }
  991.          }
  992.          if (poof == FALSE) {
  993.             /*
  994.              * see if there are any other invisible windows.  start looking
  995.              *  at the end of the window list.
  996.              */
  997.             wp = g_status.window_list;
  998.             if (wp != NULL) {
  999.                while (wp->next != NULL)
  1000.                   wp = wp->next;
  1001.             }
  1002.             while (wp != NULL && poof == FALSE) {
  1003.                if (!wp->visible)
  1004.                   poof = TRUE;
  1005.                else
  1006.                   wp = wp->prev;
  1007.             }
  1008.          }
  1009.       }
  1010.       if (poof) {
  1011.          wp->visible = TRUE;
  1012.          cline = wp->cline - (wp->top_line+wp->ruler);
  1013.          wp->top_line = top;
  1014.          wp->bottom_line = bottom;
  1015.          wp->cline = (wp->top_line+wp->ruler) + cline;
  1016.          if (wp->cline > wp->bottom_line)
  1017.             wp->cline = wp->top_line+wp->ruler;
  1018.          wp->start_col = start_col;
  1019.          wp->end_col   = end_col;
  1020.          if (start_col == 0 && end_col == g_display.ncols - 1)
  1021.             wp->vertical = FALSE;
  1022.          else
  1023.             wp->vertical = TRUE;
  1024.          check_virtual_col( wp, wp->rcol, wp->ccol );
  1025.          setup_window( wp );
  1026.          show_window_header( wp );
  1027.          if (wp->vertical)
  1028.             show_vertical_separator( wp );
  1029.  
  1030.          /*
  1031.           * The window above, below, or previously invisible becomes the new
  1032.           *  current window.
  1033.           */
  1034.          g_status.current_window = wp;
  1035.       }
  1036.    }
  1037.  
  1038.    if (!poof && g_status.stop != TRUE)
  1039.       /*
  1040.        * cannot close current window
  1041.        */
  1042.       error( WARNING, win->bottom_line, win7 );
  1043.    else {
  1044.  
  1045.       /*
  1046.        * free unused file memory if necessary
  1047.        */
  1048.       if (--file->ref_count == 0) {
  1049.  
  1050.          /*
  1051.           * if a block is marked, unmark it
  1052.           */
  1053.          if (file == g_status.marked_file) {
  1054.             g_status.marked      = FALSE;
  1055.             g_status.marked_file = NULL;
  1056.          }
  1057.  
  1058.          for (fp=g_status.file_list; fp != NULL; fp=fp->next) {
  1059.             if (fp->file_no > file->file_no)
  1060.                fp->file_no--;
  1061.          }
  1062.          file_change = file->file_no;
  1063.  
  1064.          /*
  1065.           * no window now refers to this file, so remove file from the list
  1066.           */
  1067.          if (file->prev == NULL)
  1068.             g_status.file_list = file->next;
  1069.          else
  1070.             file->prev->next = file->next;
  1071.          if (file->next)
  1072.             file->next->prev = file->prev;
  1073.  
  1074.          /*
  1075.           * free the line pointers, linked list of line pointers, and
  1076.           *  file struc.
  1077.           */
  1078.          ll = file->undo_top;
  1079.          while (ll != NULL) {
  1080.             temp_ll = ll->next;
  1081.             if (ll->line != NULL)
  1082.                my_free( ll->line );
  1083.             my_free( ll );
  1084.             ll = temp_ll;
  1085.          }
  1086.  
  1087.          ll = file->line_list;
  1088.          while (ll != NULL) {
  1089.             temp_ll = ll->next;
  1090.             if (ll->line != NULL)
  1091.                my_free( ll->line );
  1092.             my_free( ll );
  1093.             ll = temp_ll;
  1094.          }
  1095.  
  1096. #if defined( __MSC__ )
  1097.          _fheapmin( );
  1098. #endif
  1099.  
  1100.          free( file );
  1101.          if (--g_status.file_count) {
  1102.             show_file_count( g_status.file_count );
  1103.             show_avail_mem( );
  1104.          }
  1105.       }
  1106.  
  1107.       /*
  1108.        * remove the current window from the window list
  1109.        */
  1110.       if (win->prev == NULL)
  1111.          g_status.window_list = win->next;
  1112.       else
  1113.          win->prev->next = win->next;
  1114.  
  1115.       if (win->next)
  1116.          win->next->prev = win->prev;
  1117.  
  1118.       if (diff.defined  &&  (diff.w1 == win  ||  diff.w2 == win))
  1119.          diff.defined = FALSE;
  1120.  
  1121.       /*
  1122.        * free the memory taken by the window structure
  1123.        */
  1124.       free( win );
  1125.       --g_status.window_count;
  1126.  
  1127.       if (g_status.stop == FALSE) {
  1128.          g_status.current_file = wp->file_info;
  1129.          wp->file_info->dirty = LOCAL;
  1130.          make_ruler( wp );
  1131.          show_ruler( wp );
  1132.          show_window_count( g_status.window_count );
  1133.          if (file_change) {
  1134.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next)
  1135.                if (wp->visible)
  1136.                   show_window_number_letter( wp );
  1137.          } else {
  1138.             max_letter = 'a';
  1139.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next) {
  1140.                if (wp->file_info == file && wp->letter > max_letter)
  1141.                   max_letter = wp->letter;
  1142.             }
  1143.             if (max_letter < file->next_letter - 1)
  1144.                file->next_letter = max_letter + 1;
  1145.          }
  1146.       }
  1147.    }
  1148.  
  1149.    if (g_status.stop == TRUE) {
  1150.       if (g_status.sas_defined && g_status.sas_arg < g_status.sas_argc) {
  1151.          show_avail_mem( );
  1152.          for (bottom=0; bottom <= g_display.nlines; bottom++)
  1153.             eol_clear( 0, bottom, g_display.text_color );
  1154.          bottom  = g_display.nlines;
  1155.          set_prompt( win18, bottom );
  1156.          top = getkey( );
  1157.          top = getfunc( top );
  1158.          eol_clear( 0, bottom, g_display.text_color );
  1159.          if (top == RepeatGrep) {
  1160.             g_status.command = RepeatGrep;
  1161.             g_status.window_list = g_status.current_window = NULL;
  1162.             if (search_and_seize( g_status.window_list ) != ERROR)
  1163.                g_status.stop = FALSE;
  1164.          }
  1165.       }
  1166.    }
  1167. }
  1168.  
  1169.  
  1170. /*
  1171.  * Name:    create_window
  1172.  * Purpose: To allocate space for a new window structure and set up some
  1173.  *           of the relevant fields.
  1174.  * Date:    June 5, 1991
  1175.  * Passed:  window: pointer to window pointer
  1176.  *          top:    the top line of the new window
  1177.  *          bottom: the bottom line of the new window
  1178.  *          start_col:  starting column of window on screen
  1179.  *          end_col:    ending column of window on screen
  1180.  *          file:   the file structure to be associated with the new window
  1181.  * Returns: OK if window could be created
  1182.  *          ERROR if out of memory
  1183.  */
  1184. int  create_window( WINDOW **window, int top, int bottom, int start_col,
  1185.                     int end_col, file_infos *file )
  1186. {
  1187. WINDOW *wp;             /* temporary variable - use it instead of **window */
  1188. register WINDOW *prev;
  1189. int  rc;                /* return code */
  1190.  
  1191.    rc = OK;
  1192.    /*
  1193.     * allocate space for new window structure
  1194.     */
  1195.    if ((*window = (WINDOW *)calloc( 1, sizeof(WINDOW) )) == NULL) {
  1196.       /*
  1197.        * out of memory
  1198.        */
  1199.       error( WARNING, g_display.nlines, main4 );
  1200.       rc = ERROR;
  1201.    } else {
  1202.  
  1203.      /*
  1204.       * set up appropriate fields
  1205.       */
  1206.       wp              = *window;
  1207.       wp->file_info   = file;
  1208.       wp->top_line    = top+1;
  1209.       wp->bottom_line = bottom;
  1210.       wp->start_col   = start_col;
  1211.       wp->end_col     = end_col;
  1212.       wp->bin_offset  = 0;
  1213.       wp->ruler       = mode.ruler;
  1214.       make_ruler( wp );
  1215.       wp->cline       = wp->top_line + wp->ruler;
  1216.       if (start_col == 0 && end_col == g_display.ncols-1)
  1217.          wp->vertical = FALSE;
  1218.       else
  1219.          wp->vertical = TRUE;
  1220.       wp->prev        = NULL;
  1221.       wp->next        = NULL;
  1222.  
  1223.       setup_window( wp );
  1224.  
  1225.       /*
  1226.        * add window into window list
  1227.        */
  1228.       prev = g_status.current_window;
  1229.       if (prev) {
  1230.          (*window)->prev = prev;
  1231.          if (prev->next)
  1232.             prev->next->prev = *window;
  1233.          (*window)->next = prev->next;
  1234.          prev->next = *window;
  1235.       }
  1236.       if (g_status.window_list == NULL)
  1237.          g_status.window_list = *window;
  1238.  
  1239.       /*
  1240.        * record that another window is referencing this file
  1241.        */
  1242.       ++file->ref_count;
  1243.       file->dirty = LOCAL;
  1244.       ++g_status.window_count;
  1245.    }
  1246.    return( rc );
  1247. }
  1248.